//
//  BTBandwidthLimiter.swift
//  BusinessToolkit
//
//  Created by JY_NEW on 2022/3/26.
//

import Foundation

/// 带宽限制器
internal class BTBandwidthLimiter {
    let queue = DispatchQueue(label: "BTBandwidthLimiter")
    //KB代表的字节数
    private static let KB = 1024
    //一个chunk的大小，单位byte。设置一个块的大小为1M
    private static let CHUNK_LENGTH = 1024 * 1024
    
    //已经发送/读取的字节数
    private var bytesWillBeSentOrReceive = 0
    //上一次接收到字节流的时间戳——单位纳秒
    private var lastPieceSentOrReceiveTick = Date().timeIntervalSince1970
    //允许的最大速率，默认为 1024KB/s
    private var _maxRate = 1024
    var maxRate: Int {
        get {
            return _maxRate
        }
        set {
            if (newValue < 0) {
                fatalError("maxRate can not less than 0")
            }
            self._maxRate = newValue
            if (newValue == 0) {
                self.timeCostPerChunk = 0
            } else {
                self.timeCostPerChunk = TimeInterval(Self.CHUNK_LENGTH) / TimeInterval(self._maxRate * Self.KB);
            }
        }
    }
    //在maxRate的速率下，通过chunk大小的字节流要多少时间（秒）
    private var timeCostPerChunk: TimeInterval = .zero
    
    init(maxRate: Int) {
        self.maxRate = maxRate
    }
    
    public func limitNextBytes() {
        self.limitNextBytes(1);
    }
    
    public func limitNextBytes(_ len: Int) {
        self.queue.sync { [weak self] in
            guard let this = self else { return }
            this.bytesWillBeSentOrReceive += len;
            
            while (this.bytesWillBeSentOrReceive > Self.CHUNK_LENGTH) {
                let nowTick = Date().timeIntervalSince1970
                let passTime = nowTick - this.lastPieceSentOrReceiveTick
                let missedTime = this.timeCostPerChunk - passTime
                if (missedTime > 0) {
                    Thread.sleep(forTimeInterval: missedTime)
                }
                this.bytesWillBeSentOrReceive -= Self.CHUNK_LENGTH
                this.lastPieceSentOrReceiveTick = nowTick + max(missedTime, 0)
            }
        }
    }
    /// 自动心跳
    public func limitNextBytes(_ len: Int, progress: (Int) -> Void) {
        let unit = self.maxRate / 10 * 1024
        var rest = len
        while rest > 0 {
            let value = min(rest, unit)
            self.limitNextBytes(value)
            progress(value)
            rest -= unit
        }
    }
}
